#ifndef GOLBAL_H
#define GOLBAL_H

// OS
#if defined(WIN64) || defined(_WIN64)
#define OS_WIN64
#define OS_WIN32
#elif defined(WIN32) || defined(_WIN32)
#define OS_WIN32
#elif defined(ANDROID) || defined(__ANDROID__)
#define OS_ANDROID
#define OS_LINUX
#elif defined(linux) || defined(__linux) || defined(__linux__)
#define OS_LINUX
#elif defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))
#include <TargetConditionals.h>
#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
#define OS_MAC
#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
#define OS_IOS
#endif
#define OS_DARWIN
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#define OS_FREEBSD
#define OS_BSD
#elif defined(__NetBSD__)
#define OS_NETBSD
#define OS_BSD
#elif defined(__OpenBSD__)
#define OS_OPENBSD
#define OS_BSD
#elif defined(sun) || defined(__sun) || defined(__sun__)
#define OS_SOLARIS
#else
#warning "Untested operating system platform!"
#endif

#if defined(OS_WIN32) || defined(OS_WIN64)
#undef OS_UNIX
#define OS_WIN
#else
#define OS_UNIX
#endif

// ARCH
#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
#define ARCH_X86
#define ARCH_X86_32
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
#define ARCH_X64
#define ARCH_X86_64
#elif defined(__arm__)
#define ARCH_ARM
#elif defined(__aarch64__) || defined(__ARM64__)
#define ARCH_ARM64
#else
#warning "Untested hardware architecture!"
#endif

// Avoid "unused parameter" warnings
#define UNUSED(x) (void)x;

// These two macros makes it possible to turn the builtin line expander into a string literal.
#define STRINGIFY2(x) #x
#define STRINGIFY(x) STRINGIFY2(x)

#define WORD_LO(xxx) ((unsigned char)((unsigned short)(xxx)&255))
#define WORD_HI(xxx) ((unsigned char)((unsigned short)(xxx) >> 8))

#define UPCASE(c) (((c) >= 'a' && (c) <= 'z') ? ((c)-0x20) : (c))

#define DECCHK(c) ((c) >= '0' && (c) <= '9')

#define HEXCHK(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))

#define INC_SAT(val) (val = ((val) + 1 > (val)) ? (val) + 1 : (val))

#if defined(__cplusplus)

#include <string>
#include <sstream>
#include <cstdint>

// disable copy
#define DISABLE_COPY(Class)        \
    Class(const Class &) = delete; \
    Class &operator=(const Class &) = delete;

// disable move
#if (__cplusplus >= 201103L) || (_MSVC_LANG >= 201103L)
#define DISABLE_MOVE(Class)   \
    Class(Class &&) = delete; \
    Class &operator=(Class &&) = delete;
#else
#define DISABLE_MOVE(Class)
#endif

// disable copy & move
#define DISABLE_COPY_MOVE(Class) \
    DISABLE_COPY(Class)          \
    DISABLE_MOVE(Class)

// Define a macro that implements the singleton pattern
#define SINGLETON(Class)        \
public:                         \
    static Class *GetInstance() \
    {                           \
        static Class ins;       \
        return &ins;            \
    }                           \
                                \
private:                        \
    DISABLE_COPY_MOVE(Class)    \
    Class() = default;          \
    ~Class() = default;

// run function before main function
#ifndef CONSTRUCTOR_FUNCTION
#define CONSTRUCTOR_FUNCTION0(AFUNC)                  \
    namespace                                         \
    {                                                 \
        static const struct AFUNC##_ctor_class_       \
        {                                             \
            inline AFUNC##_ctor_class_() { AFUNC(); } \
        } AFUNC##_ctor_instance_;                     \
    }

#define CONSTRUCTOR_FUNCTION(AFUNC) CONSTRUCTOR_FUNCTION0(AFUNC)
#endif
// run function after main function
#ifndef DESTRUCTOR_FUNCTION
#define DESTRUCTOR_FUNCTION0(AFUNC)                    \
    namespace                                          \
    {                                                  \
        static const struct AFUNC##_dtor_class_        \
        {                                              \
            inline AFUNC##_dtor_class_() {}            \
            inline ~AFUNC##_dtor_class_() { AFUNC(); } \
        } AFUNC##_dtor_instance_;                      \
    }
#define DESTRUCTOR_FUNCTION(AFUNC) DESTRUCTOR_FUNCTION0(AFUNC)
#endif
/**
 * @brief  Example for CONSTRUCTOR_FUNCTION and DESTRUCTOR_FUNCTION
 * @example
 *  void begin()
    {
        cout << "Begin \n";
    }

    void end()
    {
        cout << "End \n";
    }

    CONSTRUCTOR_FUNCTION(begin)
    DESTRUCTOR_FUNCTION(end)

    int main(int argc, char const *argv[])
    {
        std::cout << "CONSTRUCTOR & DESTRUCTOR_FUNCTION Example!\n";
        return 0;
    }
 * @output:
        Begin
        CONSTRUCTOR & DESTRUCTOR_FUNCTION Example!
        End
 */

// get absolute value
template <typename T>
constexpr inline T Abs(const T &t)
{
    return t >= 0 ? t : -t;
}

// rounding floating point numbers
constexpr inline int Round(double d)
{
    return d >= 0.0 ? int(d + 0.5) : int(d - double(int(d - 1)) + 0.5) + int(d - 1);
}
constexpr inline int Round(float d)
{
    return d >= 0.0f ? int(d + 0.5f) : int(d - float(int(d - 1)) + 0.5f) + int(d - 1);
}
constexpr inline int64_t Round64(double d)
{
    return d >= 0.0 ? int64_t(d + 0.5) : int64_t(d - double(int64_t(d - 1)) + 0.5) + int64_t(d - 1);
}
constexpr inline int64_t Round64(float d)
{
    return d >= 0.0f ? int64_t(d + 0.5f) : int64_t(d - float(int64_t(d - 1)) + 0.5f) + int64_t(d - 1);
}

// max,min & bound
template <typename T>
constexpr inline const T &Min(const T &a, const T &b) { return (a < b) ? a : b; }
template <typename T>
constexpr inline const T &Max(const T &a, const T &b) { return (a < b) ? b : a; }
template <typename T>
constexpr inline const T &Bound(const T &min, const T &val, const T &max)
{
    return Max(min, Min(max, val));
}

// add const to non-const objects (like std::as_const)
template <typename T>
constexpr typename std::add_const<T>::type &AsConst(T &t) noexcept { return t; }
// prevent rvalue arguments:
template <typename T>
void AsConst(const T &&) = delete;

// like std::exchange
template <typename T, typename U = T>
constexpr T Exchange(T &t, U &&newValue)
{
    T old = std::move(t);
    t = std::forward<U>(newValue);
    return old;
}

// String to T, T must implement operator>>
template <typename T>
T FromString(const std::string &str)
{
    T tmp;
    std::istringstream iss(str);
    iss >> tmp;
    return tmp;
}

// String from T, T must implement operator <<
template <typename T>
std::string ToString(const T &t)
{
    // may use std::to_string;
    std::ostringstream oss;
    oss << t;
    return oss.str();
}

// swap,  use std::move ;
template <class T>
void Swap(T &a, T &b)
{
    T c(std::move(a));
    a = std::move(b);
    b = std::move(c);
}

#endif // __cplusplus
#endif // GOLBAL_H